from math import e
from py import log
from sqlalchemy import Result, select, func
from sqlalchemy.ext.asyncio import AsyncSession

from .tools import merge_tasks_orders
from scaner.core.models import User, ADS, SearchOrder
from scaner.core.config.log_config import MyLogger
from scaner.tasks.tasks import count_tasks_by_user_id, get_tasks_by_user_id

main_logger = MyLogger("main")
logger = main_logger.getChild("dashboard")  # type: ignore


def sub_stmt(user_id: int):
    return (
        select(SearchOrder.id)
        .where(SearchOrder.user_id == user_id)
        .order_by(SearchOrder.created_at.desc())
    )


async def get_total_ads_by_user_id(
    user: User,
    session: AsyncSession,
) -> int:
    logger.info("Получение количества всех объявлений в базе для пользователя")

    stmt = (
        select(func.count()).select_from(ADS).where(ADS.order_id.in_(sub_stmt(user.id)))
    )

    result: Result = await session.execute(stmt)
    total_ads_count = result.scalar()

    if not total_ads_count:
        total_ads_count = 0

    return total_ads_count


async def count_last_ads_by_user_id(
    user: User,
    session: AsyncSession,
) -> int:
    logger.info("Получение количества новых объявлений в базе для пользователя")

    sub = sub_stmt(user.id)

    last_order_result: Result = await session.execute(sub.limit(1))
    last_order = last_order_result.scalar()

    if last_order:
        stmt = (
            select(func.count()).select_from(ADS).where(ADS.order_id == last_order.id)
        )
        result: Result = await session.execute(stmt)
        total_last_ads_count = result.scalar()

        if not total_last_ads_count:
            total_last_ads_count = 0

    else:
        total_last_ads_count = 0

    return total_last_ads_count


async def get_main_statistics(
    user: User,
    session: AsyncSession,
) -> dict[str, int]:
    logger.info("Получение статистики для пользователя")

    total_ads_count = await get_total_ads_by_user_id(user, session)
    total_last_ads_count = await count_last_ads_by_user_id(user, session)
    active_tasks_count = count_tasks_by_user_id(user.id)

    return {
        "all_ads_count": total_ads_count,
        "last_ads_count": total_last_ads_count,
        "active_tasks_count": active_tasks_count,
    }


async def get_active_tasks_by_user_id(
    user: User,
    session: AsyncSession,
) -> list[dict]:
    logger.info("Получение активных задач для пользователя")

    active_tasks: list[dict[str, int]] = get_tasks_by_user_id(user.id)
    list_of_orders = [item.get("order_id") for item in active_tasks]

    stmt = select(SearchOrder).where(SearchOrder.id.in_(list_of_orders))
    result: Result = await session.execute(stmt)

    orders_in_tasks: list[SearchOrder] = list(result.scalars().all())

    return merge_tasks_orders(active_tasks, orders_in_tasks)


async def get_last_five_ads_by_user_id(
    user: User,
    session: AsyncSession,
) -> list[ADS]:
    logger.info("Получение последних 5 объявлений в базе для пользователя")

    try:
        last_order_result: Result = await session.execute(sub_stmt(user.id).limit(1))
        last_order = last_order_result.scalar()

        if last_order:
            stmt = (
                select(ADS)
                .where(ADS.order_id == last_order.id)
                .order_by(ADS.created_at.desc())
                .limit(5)
            )
            result: Result = await session.execute(stmt)
            return list(result.scalars().all())

    except Exception as e:
        logger.error(f"Ошибка получения данных из БД, ошибка: {e}")

    return []


async def get_data_for_chart(
    user: User,
    session: AsyncSession,
) -> dict:
    logger.info("Получение данных для графика")
    data_for_chart: list[tuple] = []

    try:
        orders_result: Result = await session.execute(sub_stmt(user.id))
        orders: list[SearchOrder] = list(orders_result.scalars().all())

        if orders:
            for order in orders:
                stmt = (
                    select(func.count())
                    .select_from(ADS)
                    .where(ADS.order_id == order.id)
                )
            result: Result = await session.execute(stmt)
            total_last_ads_count = result.scalar()

            if not total_last_ads_count:
                total_last_ads_count = 0

            data_for_chart.append(
                (order.created_at.strftime("%d/%m"), total_last_ads_count)
            )

        list_of_categories, list_of_data = map(list, zip(*data_for_chart))
        return {
            "categories": list_of_categories,
            "data": list_of_data,
        }

    except Exception as e:
        logger.error(f"Ошибка получения данных из БД, ошибка: {e}")

    return {
        "categories": ["31/12", "23/02", "8/03", "01/05", "09/05", "12/06"],
        "data": [10, 0.5, 1.5, 1, 5.5, 0.5],
    }
